package com.maschinenstuermer.profiler.model.impl;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;

@XmlType
@XmlAccessorType(XmlAccessType.FIELD)
public class Metrics {	
	@XmlAttribute(required=true)
	private long totalTimeNs;
	
	@XmlAttribute(required=true)
	private int calls;
	
	@XmlAttribute(required=true)
	private long maxTimeNs = Long.MIN_VALUE;
	
	@XmlAttribute(required=true)
	private long minTimeNs = Long.MAX_VALUE;
	
	private transient long lastTickNs = -1;
	
	private transient long executionTimeNs;
	
	public Metrics() {
	}

	public void startOrContinue(long tickNs) {
		lastTickNs = tickNs;
	}
	
	public void pause(long stopTickNs) {
		executionTimeNs = stopTickNs - lastTickNs;
		lastTickNs = -1;
	}
	
	public void finish(long tickNs) {
		assert lastTickNs >= 0;
		executionTimeNs += tickNs - lastTickNs;
		calls++;
		totalTimeNs += executionTimeNs;
		minTimeNs = Math.min(minTimeNs, executionTimeNs);
		maxTimeNs = Math.max(maxTimeNs, executionTimeNs);
	}

	public int getCalls() {
		return calls;
	}

	public long getTotalTimeNs() {
		return totalTimeNs;
	}

	public long getMaxTimeNs() {
		return maxTimeNs;
	}

	public long getMinTimeNs() {
		return minTimeNs;
	}

	public void add(Metrics metrics) {
		this.calls += metrics.getCalls();
		this.totalTimeNs += metrics.getTotalTimeNs();
		this.maxTimeNs = Math.max(this.maxTimeNs , metrics.getMaxTimeNs());
		this.minTimeNs = Math.min(this.minTimeNs , metrics.getMinTimeNs());
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + calls;
		result = prime * result + (int) (maxTimeNs ^ (maxTimeNs >>> 32));
		result = prime * result + (int) (minTimeNs ^ (minTimeNs >>> 32));
		result = prime * result + (int) (totalTimeNs ^ (totalTimeNs >>> 32));
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Metrics other = (Metrics) obj;
		if (calls != other.calls)
			return false;
		if (maxTimeNs != other.maxTimeNs)
			return false;
		if (minTimeNs != other.minTimeNs)
			return false;
		if (totalTimeNs != other.totalTimeNs)
			return false;
		return true;
	}
}
